/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Commands.h"
#include "AliasList.h"
#include "CmdVisitor.h"
#include "Global.h"
#include "Session.h"
#include "StringBuilder.h"
#include "Table.h"
#include "myassert.h"
#include "Utils.h"
#include "color.h"
#include "config.h"

#include "SessionManager.h"
#include "PlayerSession.h"
#include "CommServer.h"
#include "Parser.h"
#include "Activity.h"

#include "Room.h"

#include "Equipment.h"
#include "ElevatorController.h"
#include "MudContainer.h"
#include "MudCreature.h"
#include "MudDoor.h"
#include "MudConsumable.h"
#include "MudExit.h"
#include "MudItem.h"
#include "MudKey.h"
#include "MudObject.h"
#include "MudPlayer.h"
#include "MudWearable.h"
#include "Stats.h"
#include "Trade.h"


#define ROOM_FIND(a, b) MudObject* a = room->findObject(b); \
    if (a == 0) { session.write() << "There is no " << b << " here.\n"; return; }

#define ON_PLAYER_FIND(a, b) MudItem* a = player.findItem(b); \
    if (a == 0) { session.write() << "You don't have a " << b << ".\n"; return; }

#define INVENTORY_FIND(a, b) MudItem* a = player.findInInventory(b); \
    if (a == 0) { session.write() << "You don't have a " << b << ".\n"; return; }

#define EQUIPMENT_FIND(a, b) MudWearable* a = player.findInEquipment(b); \
    if (a == 0) { session.write() << "You don't have a " << b << ".\n"; return; }

#define INVENTORY_FIND_CHECK_EQUIP(a, b) \
    MudItem* a = player.findInInventory(b); \
    if (a == 0) {  \
        if (player.findInEquipment(b)) { \
            session.write() << "Please remove it first.\n"; \
        } else { \
            session.write() << "You don't have a " << b << ".\n"; \
        } \
        return; \
    }        

#define PLAYER_ROOM_FIND(a, b) MudObject* a = player.findItem(b); \
    if (a == 0) { a = room->findObject(b); } \
    if (a == 0) { session.write() << "There is no " << b << " here.\n"; return; } 

#define OBJECT_CAST(a, b, c, d) a* b = TypeVisitor<a>::getType(c); \
    if (b == 0) { session.write() << d; return; }

#define ROOM_OBJECT_CHECK(a, b) \
    MudPlayer& player = session.getPlayer(); \
    Room* room = player.getRoom(); \
    ROOM_FIND(tmpObject, arg); \
    OBJECT_CAST(a, object, *tmpObject, b);

#define FOREACH_PLAYER  for (SessionManager::PlayerSessionsConstIter iter=players.begin(); iter!=players.end(); ++iter)

using namespace Chronos;
using namespace std;

void HelpCommand::execute(Session& session) {
    const char* help = ""
"            ___   ___     ______     ___        _______ \n"
"           /  /\\ /  /\\   /  ___/\\   /  /\\      /  __  /\\\n"
"          /  /__/  / /  /  /__ \\/  /  / /     /  /_/ / /\n"
"         /  ___   / /  /  ___/\\   /  / /     /  ____/ / \n"
"        /  /\\_/  / /  /  /___\\/  /  /___    /  /\\___\\/\n"
"       /__/ //__/ /  /______/\\  /______/\\  /__/ /\n"
"       \\__\\/ \\__\\/   \\______\\/  \\______\\/  \\__\\/\n";
    session.write() << help;
	Parser& parser = Global<SessionManager>()->getParser();
    session.write() << "List of commands:\n";
    parser.showCommands(session);
}


void QuitCommand::execute(Session& session) {
    session.write() << "Goodbye!\n";
    session.setLogout();
}


void DateCommand::execute(Session& session) {
    session.write() << Utils::getDate();
}


void ChangePasswordCommand::execute(Session& session, const string& arg) {
    if (arg.size() < 6) {
        session.write() << "Password should be at least 6 characters long!\n";
        return;
    }
    session.changePassword(arg);
    session.write() << "new password accepted.\n";
}


class LookAtVisitor : public ObjectVisitor {
public:
    LookAtVisitor(const string& playerName_)
        : playerName(playerName_)
    {}
    virtual bool handle(MudObject* object) {
        if (object->isVisible() && object->getName() != playerName) {
			MudExit* isExit = TypeVisitor<MudExit>::getType(*object);
			if (!isExit) buffer << "  " << object->getName() << '\n';
		}
        return true;
    }
    const StringBuilder& getResult() const { return buffer; }
private:
    string playerName;
    StringBuilder buffer;
};


void LookCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();
    session.write() << room->getLongDescription();
    LookAtVisitor visitor(player.getName());
    room->visitObjects(visitor);
    const StringBuilder& result = visitor.getResult();
    if (!result.isEmpty()) {
        session.write() << "You also see:\n" << result;
    }
}


void LookAtCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();
    if (player.getName() == arg) {
        session.write() << "You look at yourself.\n";
        return;
    }
    PLAYER_ROOM_FIND(object, arg);

    session.write() << object->getDescription() << '\n';
}


void OpenCommand::execute(Session& session, const string& arg) {
    ROOM_OBJECT_CHECK(MudOpenable, "You cannot open that.\n");
   	object->open(player); 
}


void CloseCommand::execute(Session& session, const string& arg) {
    ROOM_OBJECT_CHECK(MudOpenable, "You cannot close that.\n");
   	object->close(player); 
}


void LockCommand::execute(Session& session, const string& arg, const string& arg2) {
    ROOM_OBJECT_CHECK(MudLockable, "You cannot lock that.\n");
    ON_PLAYER_FIND(keyItem, arg2);
    OBJECT_CAST(MudKey, key, *keyItem, "That's not a key.\n");
    object->lock(player, *key);
}


void UnlockCommand::execute(Session& session, const string& arg, const string& arg2) {
    ROOM_OBJECT_CHECK(MudLockable, "You cannot unlock that.\n");
    ON_PLAYER_FIND(keyItem, arg2);
    OBJECT_CAST(MudKey, key, *keyItem, "That's not a key.\n");
    object->unlock(player, *key);
}


void PushCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();
    ROOM_FIND(object, arg);
    OBJECT_CAST(ElevatorButton, button, *object, "You cannot push that.\n");

	button->push(player);
}


void GreetCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();

    if (player.getName() == arg) {
        session.write() << "You greet yourself, hello\n";
        return;
    }
    ROOM_FIND(object, arg);
    OBJECT_CAST(MudPlayer, targetPlayer, *object, "You cannot greet that.\n");

    session.write() << "You greet " << arg << '\n';
    targetPlayer->write(player.getName() + " greets you.\n");
}


void SayCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();
    
    session.write() << "You say: '" << arg << "'\n";
    room->showText(player.getName() + " says: '" + arg + "'", player);
}


void AttackCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();
    
    if (player.getName() == arg) {
        session.write() << "You cannot attack yourself!\n";
        return;
    }
    ROOM_FIND(target, arg);
    OBJECT_CAST(MudMobile, targetMobile, *target, "You cannot attack that.\n");
    
    if (player.isInCombat()) {
        session.write() << "You are already in combat!\n";
        return;
    }
    player.addTarget(*targetMobile);
	room->showText(player.getName() + " attacks " + targetMobile->getName() + ".", player, *targetMobile);
}


class WhoVisitor : public SessionVisitor {
public:
    WhoVisitor(Table& table_) : table(table_) {}
    virtual void handle(PlayerSession& session) {
        table.addCell(session.getName());
        table.addCell(session.getStatus());
        table.addCell(session.getPlayer().getRoom()->getName());
    }
    Table& table;
};


void WhoCommand::execute(Session& session) {
    session.write() << "List of players:\n";
    Table table(3);
    table.setMargin(3);
    WhoVisitor visitor(table);
    Global<SessionManager>()->visitSessions(visitor);
    table.write(session.write());
}


void movePlayer(Session& session, const string& direction) {
    MudPlayer& player = session.getPlayer();
    Room* oldRoom = player.getRoom();
    MudObject* object = oldRoom->findObject(direction);
    const char* cannot = "You can't go there.\n";
    if (object == 0) {
        session.write() << cannot;
        return;
    }
    OBJECT_CAST(MudExit, exitObj, *object, cannot);
    exitObj->pass(player);
}


void NorthCommand::execute(Session& session) { movePlayer(session, "north"); }

void EastCommand::execute(Session& session) { movePlayer(session, "east"); }

void SouthCommand::execute(Session& session) { movePlayer(session, "south"); }

void WestCommand::execute(Session& session) { movePlayer(session, "west"); }

void UpCommand::execute(Session& session) { movePlayer(session, "up"); }

void DownCommand::execute(Session& session) { movePlayer(session, "down"); }


void StatusCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    const Stats& stats = player.getStats();
    session.write() << "hp " << stats.getHealth() << '[' << stats[Stats::maxHealth] << "]\n";
    Table table(2);
    for (int i=1; i<Stats::MAX; i++) {
        table.addCell(Stats::toStr[i]);
        table.addCell(stats[(Stats::Stat)i]);
    }
    table.write(session.write());
}


void pickupItem(MudPlayer& player, Room* room, MudItem* item) {
    item->pickup();
    player.write("You pickup " + item->getName() + ".\n");
    room->showText(player.getName() + " picks up the " + item->getName() + ".", player);
}

class PickupAllVisitor : public ObjectVisitor {
public:
    PickupAllVisitor(MudPlayer& player_)
        : player(player_)
        , room(player.getRoom())
    {}
    virtual bool handle(MudObject* object) {
        if (!object->isVisible()) return true;
		MudItem* item = TypeVisitor<MudItem>::getType(*object);
        if (item != 0) {
            if (item->canPickup(player)) {
                pickupItem(player, room, item);
                item->setRoom(0);
                player.addItem(item);
                return false;
            }
        }
        return true;
    }
private:
    MudPlayer& player;
    Room* room;
};

void PickupCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();
	
	if (arg == "all") {
        PickupAllVisitor visitor(player);
        room->visitObjects(visitor);
	} else {
    	MudObject* object = room->findObject(arg);
	    if (object == 0) {
   		 	object = player.findItem(arg);
	    	if (object != 0) session.write() << "You already have that.\n";
			else session.write() << "There is no " << arg << " here.\n";
        	return;
	    } 
    	OBJECT_CAST(MudItem, item, *object, "You cannot pick that up.\n");
        if (item->canPickup(player)) {
            pickupItem(player, room, item);
            room->removeObject(item);
            player.addItem(item);
        }
	}
}


void dropItem(MudPlayer& player, Room* room, MudItem* item) {
    player.removeItem(item);
    room->addObject(item);
    room->showText(player.getName() + " drops a " + item->getName() + ".", player);
    player.write("dropping " + item->getName() + ".\n");
}

class DropVisitor : public ItemVisitor {
public:
    DropVisitor(MudPlayer& player_) : count(0), player(player_), room(player.getRoom()) {}
    virtual void handle(MudItem* item) {
        dropItem(player, room, item);
        count++;
    }
    int count;
private:
    MudPlayer& player;
    Room* room;
};

void DropCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();

	if (arg == "all") {
        DropVisitor visitor(player);
        player.visitInventory(visitor);
        if (visitor.count == 0) session.write() << "Nothing to drop.\n";
    } else {
        INVENTORY_FIND_CHECK_EQUIP(item, arg);
        Room* room = player.getRoom();
        dropItem(player, room, item);
    }
}


class InventoryVisitor : public ConstItemVisitor {
public:
    InventoryVisitor() : weight(0) {}
    virtual void handle(MudItem* item) {
        buffer << "   " << item->getName() << '\n';
        weight += item->getWeight();
    }

    StringBuilder buffer;
    int weight;
};


void InventoryCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    InventoryVisitor visitor;
    player.visitInventory(visitor);

    session.write() << "inventory:\n";
    if (visitor.buffer.isEmpty()) {
        session.write() << "You are carrying nothing.\n";
    } else {
        session.write() << visitor.buffer;
    }

    const Equipment& equip = player.getEquipment();
	session.write() << "credits: " << player.getCredits() << "   total weight: " << visitor.weight + equip.getWeight() << "\n";
}


void PutInCommand::execute(Session& session, const string& arg1, const string& arg2) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();
    INVENTORY_FIND_CHECK_EQUIP(item, arg1);
    ROOM_FIND(object, arg2);
    OBJECT_CAST(MudContainer, container, *object, "You cannot put something in that.\n");
    
    if (!container->canAccess(player)) return;

    player.removeItem(item);
    container->addItem(item);
    session.write() << "OK\n";
    room->showText(player.getName() + " puts a " + arg1 + " in the " + arg2 + ".", player);
}


void DisposeCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    MudItem* item = player.findInInventory(arg);
    if (item == 0) { 
        if (player.findInEquipment(arg)) {
            session.write() << "Please remove it first.\n";
        } else {
            session.write() << "You don't have a " << arg << ".\n";
        }
        return;
    }        

    player.removeItem(item);
    delete item;
	session.write() << "OK\n";
}

void GetFromCommand::execute(Session& session, const string& arg1, const string& arg2) {
    MudPlayer& player = session.getPlayer();
	Room* room = player.getRoom();
    ROOM_FIND(object, arg2);
    OBJECT_CAST(MudContainer, container, *object, "You cannot get something from that.\n");

    if (!container->canAccess(player)) return;

	if (arg1 == "all") {
		MudContainer::Items items = container->getItems();
		for (MudContainer::ItemsIter iter=items.begin(); iter!=items.end(); ++iter) {
            if (!(*iter)->isVisible()) continue;
			moveItem(player, container, *iter);
		}
	} else {
		MudItem* item = container->findItem(arg1);
		if (item == 0) {
			session.write() << "There is no " << arg1 << " in the " << arg2 << ".\n";
	     	return;
		} 
		moveItem(player, container, item);
	}
}


void GetFromCommand::moveItem(MudPlayer& player, MudContainer* container, MudItem* item) {
	if (item->canPickup(player)) {
		item->pickup();
		container->removeItem(item);
		player.addItem(item);
		player.write("You pickup " + item->getName() + ".\n");
	}
}


void DrinkCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    ON_PLAYER_FIND(item, arg);
    OBJECT_CAST(MudDrink, drink, *item, "You cannot drink that.\n");

    player.removeItem(drink);
    drink->drink(player);
    delete drink;
}


void EatCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    ON_PLAYER_FIND(item, arg);
    OBJECT_CAST(MudFood, food, *item, "You cannot eat that.\n");

    player.removeItem(food);
    food->eat(player);
    delete food;
}


void WearCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    if (player.findInEquipment(arg)) {
        session.write() << "You're already wearing that!\n";
        return;
    }
     
    INVENTORY_FIND(item, arg);
    OBJECT_CAST(MudWearable, equip, *item, "You cannot wear that.\n");
    player.wear(equip);
}


void UnwearAllCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    const Equipment& equipment = player.getEquipment();
    bool isEmpty = true;
    for (int i=0; i<Equipment::MAX; ++i) {
        MudWearable* item = equipment[(Equipment::Slot)i];
        if (item) {
            isEmpty = false;
            player.unwear(item);
        }
    }
    if (isEmpty) session.write() << "You're not wearing anything.\n";
}


void UnwearCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    MudWearable* equip = player.findInEquipment(arg);
    if (equip == 0) {
        session.write() << "You're not wearing that.\n";
        return;
    }
    player.unwear(equip);
}


void ShowEquipCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    session.write() << "equipment:\n";
    const Equipment& equipment = player.getEquipment();
    Table table(2);
    for (int i=0; i<Equipment::MAX; ++i) {
        table.addCell(Equipment::toStr[i]);
        MudWearable* equip = equipment[(Equipment::Slot)i];
        if (equip) table.addCell(equip->getName());
        else table.addCell("-");
    }
    table.write(session.write());
}


void AliasCommand::execute(Session& session, const std::string& arg1, const std::string& arg2) {
	if (arg1 == "alias" || arg1 == "unalias") {
		session.write() << "Cannot alias 'alias' or 'unalias'.\n";
		return;
	}
	if (arg1 == arg2) {
		session.write() << "Why would you want to alias something to itself?\n";
		return;
	}
	AliasList& aliasList = session.getAliases();
	const string& value = aliasList.find(arg1);
	if (value != "") {
		session.write() << "changing alias '" << arg1 << "' from '" << value << "' to '" << arg2 << "'.\n";
		aliasList.add(arg1, arg2);
		return;
	}
	if (aliasList.size() == Config::MAX_ALIASES) {
		session.write() << "Already at maximum number of aliases (" << Config::MAX_ALIASES << ").\n";
		return;
	}
	aliasList.add(arg1, arg2);
	session.write() << "added alias '" << arg1 << "' -> '" << arg2 << "'.\n";
}


void UnAliasCommand::execute(Session& session, const std::string& arg1) {
	AliasList& aliasList = session.getAliases();
	if (!aliasList.remove(arg1)) {
		session.write() << "no alias named that way.\n";
		return;
	}
	session.write() << "removed alias '" << arg1 << "'.\n";
}


void AliasListCommand::execute(Session& session) {
    session.getAliases().printAliases(session.write());
}


void SettingsCommand::execute(Session& session) {
    session.getSettings().print(session.write());
}


void SetCommand::execute(Session& session, const string& arg1, const string& arg2) {
    PlayerSettings& settings = session.getSettings();
    settings.setOption(session.write(), arg1, arg2);
}


void CommCommand::execute(Session& session) {
	printUsage(session);
}


void CommListCommand::execute(Session& session) {
	Global<CommServer>()->listChannels(session);
}


void CommChatCommand::execute(Session& session, const string& arg1, const string& arg2) {
	Global<CommServer>()->write(session, arg1, arg2);
}


void CommJoinCommand::execute(Session& session, const string& channel) {
	Global<CommServer>()->join(session, channel);
}


void CommLeaveCommand::execute(Session& session, const string& channel) {
	Global<CommServer>()->leave(session, channel);
}


void CommShowCommand::execute(Session& session, const string& channel) {
	Global<CommServer>()->showChannelMembers(session, channel);
}


void CommCreateCommand::execute(Session& session, const string& channel) {
	Global<CommServer>()->addPlayerChannel(session, channel, ANSI_BROWN);
}


void PromptCommand::execute(Session& session, const string& arg) {
    const char* str = arg.c_str();
    while (*str != 0) {
        if (*str == '%') {
            ++str;
            switch (*str) {
            case 'h':
            case 'H':
            case 'd':
                break;
            default:
                session.write() << *str << " is not a valid option.\n";
                return;
            }
        }
        ++str;
    }
    session.setPrompt(arg + " ");
}


void TellCommand::execute(Session& session, const string& arg1, const string& arg2) {
    PlayerSession* target = Global<SessionManager>()->findPlayerSession(arg1);
    if (target) {
		target->write() << session.getName() << " tells you: " << arg2 << '\n';
		return;
	}	
	session.write() << "No such player online.\n";
}

namespace Chronos {

class SearchActivity : public Activity {
public:
    SearchActivity(Session& session_) : session(session_) {}
    virtual unsigned int start() {
        session.write() << "You start searching.\n"; 
        return seconds(4);
    }
    virtual void cancel() { session.write() << "You stop searching.\n"; }
    virtual unsigned int progress() {
        int res = Utils::roll(1, 5);
        if (res == 1) {
            session.write() << "You finish searching and find nothing.\n"; 
            return 0;
        }
        session.write() << "You continue searching.\n"; 
        return seconds(4);
    }
private:
    Session& session;
};

}

void SearchCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    if (player.isInCombat()) {
        session.write() << "You cannot search during combat.\n";
        return;
    }
    player.setActivity(new SearchActivity(session));
}


void StopCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    if (!player.cancelActivity()) {
        session.write() << "no activity to stop.\n";
    }
}


void PlayedCommand::execute(Session& session) {
    unsigned int playTime = session.getPlayTime();
    session.write() << "You played for " << Utils::toDurationString(playTime);
    unsigned int totalTime = session.getTotalTime();
    session.write() << " (total: " << Utils::toDurationString(totalTime) << ")\n";
}


#define CHECK_TRADE \
    if (!player.inTrade()) { \
        player.write("You're not in a trade.\n"); \
        return; \
    }

void TradeHelpCommand::execute(Session& session) {
    session.write() << "Trade help:\n";
    session.write() << "trade with [player] - starts new trade with player.\n";
    session.write() << "trade stop - cancels trade.\n";
    session.write() << "trade accept - accepts trade.\n";
    session.write() << "trade add [item] - adds item to trade.\n";
    session.write() << "trade credits [amount] - adds credits to trade.\n";
    session.write() << "trade show - shows contents of current trade.\n";
    session.write() << "trade see [item] - show info about [item] in trade.\n";
}


void TradeStartCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    if (player.getName() == arg) {
        session.write() << "You cannot trade with yourself.\n";
        return;
    }
    if (player.inTrade()) {
        session.write() << "You are already in a trade.\n";
        return;
    }
    if (player.isInCombat()) {
        session.write() << "You cannot trade during combat.\n";
        return;
    }

    Room* room = player.getRoom();
    ROOM_FIND(object, arg);
    OBJECT_CAST(MudPlayer, player2, *object, "You cannot trade with that!\n");
    if (player2->inTrade()) {
        session.write() << arg << " is already in trade.\n";
        return;
    }
    if (player2->isInCombat()) {
        session.write() << player2->getName() << " is in combat.\n";
        return;
    }
    new Trade(player, *player2);
}


void TradeStopCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    CHECK_TRADE;
    player.getTrade()->cancel();
}


void TradeAcceptCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    CHECK_TRADE;
    player.getTrade()->accept(player);
}


void TradeItemCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    CHECK_TRADE;
    INVENTORY_FIND_CHECK_EQUIP(item, arg);
    player.removeItem(item);
    player.getTrade()->addItem(player, *item);
}


void TradeCreditsCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    CHECK_TRADE;
    int amount = atoi(arg.c_str());
    if (amount < 0) {
        player.write("You cannot trade negative amounts.\n");
        return;
    }
    unsigned int oldAmount = player.getCredits();
    if ((unsigned int)amount > oldAmount) {
        player.write("You don't have that many credits.\n");
        return;
    }
    player.setCredits(oldAmount - amount);
    player.getTrade()->addCredits(player, amount);        
}


void TradeShowCommand::execute(Session& session) {
    MudPlayer& player = session.getPlayer();
    CHECK_TRADE;
    player.getTrade()->show(session);
}


void TradeSeeCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    CHECK_TRADE;
    MudItem* item = player.getTrade()->findItem(arg);
    if (item == 0) {
        player.write("There's no such item in trade.");
        return;
    }
    player.write(item->getDescription() + '\n');
}


void MyDefaultCommand::execute(Session& session, const string& arg) {
    MudPlayer& player = session.getPlayer();
    Room* room = player.getRoom();
    MudObject* object = room->findObject(arg);
    if (object == 0) {
        session.write() << "What?\n";
   		return;
    }
    MudExit* exitObj = TypeVisitor<MudExit>::getType(*object);
    if (exitObj != 0) {
        exitObj->pass(player);
    	return;
    }    
    session.write() << "What?!\n";
}

